<?php
/**
 * Created by PhpStorm.
 * User: jjj
 * Date: 2017/8/31
 * Time: 17:50
 */

namespace app\common\model;


use app\api\model\curriculum\Curriculum;
use app\api\model\DrawPercentageRecord;
use app\api\model\live\Live;
use app\api\model\special\UserSubscribeSpecial;
use app\api\model\user\Users;
use app\common\lib\BaseModel;
use app\common\lib\pay\PayFactory;
use app\common\model\app\ConstLinkType;
use app\common\model\sale\Gifts;
use app\common\utils\DateTimeUtil;
use library\contractSignature;
use library\JPushZDY;
use library\ServerAPI;
use think\Db;
use think\db\Query;
use think\Exception;
use think\Log;
use think\Model;

/**
 * @property mixed bill_user
 * @property bool bill_have_paid
 * @property mixed bill_item_type
 * @property mixed bill_item_id
 * @property mixed bill_id
 * @property mixed bill_pay_amount
 * @property mixed bill_item_title
 * @property mixed bill_item_detail
 * @property mixed bill_paytime
 * @property mixed bill_createtime
 * @property mixed pay_trade_no
 * @property mixed bill_no
 * @property mixed bill_payable_amount
 * @property mixed bill_pay_method
 * @property mixed credit_cost
 * @property mixed bill_trade_way
 * @property mixed bill_source
 * @property mixed bill_type
 * @property mixed err_log
 * @property string|object|Gifts gifts
 * @property string|object|array apple_pay
 * @property bool is_sandbox
 */
class BuyBill extends BaseModel
{
    protected $table = 'buy_bill';
    protected $pk = 'bill_id';

    const JSON_FIELDS = [
        'gifts',
        'apple_pay',
    ];

    const TITLE_PREFIX = '掌乾财经-';

    // 商品类型，具体商品对象
    const BUY_ITEM_CURRICULUM   = 1; // 课程
    const BUY_ITEM_LIVE         = 2; // 直播
    const BUY_ITEM_SPECIAL      = 3; // 专栏订阅 ZK(20180117)
    /**
     * *** 每个Item的类需要实现下面三个静态方法 ***
     *
     * 用于支付的方法，购买支付后的处理
     * @param $bill_id
     * @param $uid
     * @param $curriculum_id
     * @param $bill
     * @throws Exception
     * public static function afterBought($bill_id, $uid, $curriculum_id, BuyBill $bill)
     *
     * 检查是否购买
     * @param $uid
     * @param $curriculum_id
     * @return bool|mixed
     * public static function checkBought($uid, $curriculum_id)
     *
     * 用于支付的方法，计算商品总价格、获取商品信息等
     * @param $uid
     * @param $curriculum_id
     * @return array|bool
     * public static function getBuyInfo($uid, $curriculum_id)
     *
     * *** ***
     *
     *
     * @var array
     */
    public static $BuyItems = [
        self::BUY_ITEM_CURRICULUM   => Curriculum::class,
        self::BUY_ITEM_LIVE         => Live::class,
        self::BUY_ITEM_SPECIAL      => UserSubscribeSpecial::class, // ZK(20180117)
    ];
    /**
     * @param integer $type
     * @return Curriculum|Live|UserSubscribeSpecial
     */
    public static function getBuyItem($type) {
        return self::$BuyItems[$type];
    }
    public static $BuyItemNames = [
        self::BUY_ITEM_CURRICULUM   => '课程',
        self::BUY_ITEM_LIVE         => '直播',
        self::BUY_ITEM_SPECIAL      => '专栏', // ZK(20180117)
    ];
    public static function getBuyItemName($item) {
        return self::$BuyItemNames[$item] ?? null;
    }


    // 购买类型，购买消耗的货币或积分等
    const PAY_TYPE_CASH = 1;
    const PAY_TYPE_CREDIT = 2;
    const PAY_TYPE_MIXED = 3;
    public static $PayTypeNames = [
        self::PAY_TYPE_CASH     => '现金购买',
        self::PAY_TYPE_CREDIT   => '积分兑换',
        self::PAY_TYPE_MIXED    => '现金和积分混合使用',
    ];
    public static function getPayTypeName($payType) {
        return self::$PayTypeNames[$payType] ?? null;
    }


    // 交易类型，进行交易的方式，主要用来区分线上和线下，字段[bill_trade_way]
    const TRADE_WAY_ONLINE = 1;
    const TRADE_WAY_OFFLINE = 2;
    public static $TradeWayNames = [
        self::TRADE_WAY_ONLINE  => '在线交易',
        self::TRADE_WAY_OFFLINE => '线下交易',
    ];
    public static function getTradeWayName($tradeWay) {
        return self::$TradeWayNames[$tradeWay] ?? null;
    }

    // 订单类型，字段[bill_type]
    const BILL_TYPE_CASH_PAY         = 1;
    const BILL_TYPE_CREDIT_EXCHANGE  = 2;
    const BILL_TYPE_CREDIT_CASH      = 3;
    const BILL_TYPE_GIFT             = 4;
    public static $BuyTypeNames = [
        self::BILL_TYPE_CASH_PAY         => '支付购买',
        self::BILL_TYPE_CREDIT_EXCHANGE  => '积分兑换',
        self::BILL_TYPE_CREDIT_CASH      => '积分抵扣',
        self::BILL_TYPE_GIFT             => '赠送',
    ];
    public static function getBuyTypeName($buyType) {
        return self::$BuyTypeNames[$buyType] ?? null;
    }

    public function simpleInfo() {
        return [
            'bill_id' => $this->bill_id,
            'bill_item_type' => $this->bill_item_type,
            'bill_item_id' => $this->bill_item_id,
            'bill_payable_amount' => $this->bill_payable_amount,
            'bill_pay_amount' => $this->bill_pay_amount,
            'bill_createtime' => $this->bill_createtime,
            'bill_no' => $this->bill_no,
            'bill_item_title' => $this->bill_item_title,
            'bill_item_detail' => $this->bill_item_detail,
            'apple_pay' => $this->apple_pay,
        ];
    }

    /**
     * 生成order字符串
     *
     * @param $uid
     * @return string
     */
    public static function generateOrderNo($uid) {
        $time = date('YmdHis',$_SERVER['REQUEST_TIME']);
        $uidStr = sprintf('%010d', $uid);
        $order = $time . $uidStr . mt_rand(100000, 999999);
        return $order;
    }

    /**
     * 产生苹果内购信息结构
     *
     * @param $applePayPrice
     * @param $applePayId
     * @return \stdClass
     */
    public static function applePayObject($applePayPrice, $applePayId) {
        $obj = new \stdClass();
        $obj->price = $applePayPrice;
        $obj->id = $applePayId;
        return $obj;
    }

    /**
     * self::checkBought() 的快捷调用
     *
     * @return bool
     */
    public function chkBought() {
        return self::checkBought($this->bill_item_type, $this->bill_user, $this->bill_item_id);
    }

    /**
     * 检查是否购买
     * @param $buyItem integer 购买对象类型
     * @param $uid integer 用户id
     * @param $item_id integer 购买对象id
     * @return bool
     */
    public static function checkBought($buyItem, $uid, $item_id) {

        $Item = self::getBuyItem($buyItem);
        if (method_exists($Item,'checkBought')) {
            $re = $Item::checkBought($uid,$item_id);
        } else {
            $sql = <<<SQL
SELECT exists
(
SELECT * FROM buy_bill 
WHERE bill_user=:uid AND bill_item_type=:type AND bill_item_id=:id AND bill_have_paid=TRUE 
) AS e
SQL;
            $re = Db::query($sql, ['uid'=>$uid,'type'=>$buyItem,'id'=>$item_id]);
            $re = $re[0]['e'];
        }

        return $re ?? false;
    }

    /**
     * @param $buyItem
     * @param $uid
     * @param $itemId
     * @return BuyBill|null
     */
    public static function getExistsItem($buyItem, $uid, $itemId) {
        $bill = self::get(function (Query $query) use ($buyItem,$uid,$itemId) {
            $query->where('bill_user', $uid);
            $query->where('bill_item_type', $buyItem);
            $query->where('bill_item_id', $itemId);
            $query->where('bill_have_paid',false);
            $query->order('bill_id','desc');
        });
        return $bill;
    }

    /**
     * 获取上次的下单未支付成功的
     *
     * @param $buyItem
     * @param $uid
     * @param $itemId
     * @return null|static
     */
    public static function getLastUnFinish($buyItem, $uid, $itemId) {
        return self::get([
            'bill_user' => $uid,
            'bill_item_type' => $buyItem,
            'bill_item_id' => $itemId,
        ]);
    }

    /**
     * 获取总价格、产品信息等
     *
     * @param $buyItem
     * @param $uid
     * @param $itemId
     * @return array|bool
     */
    public static function getBuyInfo($buyItem, $uid, $itemId) {

        $class = self::getBuyItem($buyItem);

        return $class::getBuyInfo($uid, $itemId);
    }

    /**
     * 记录日志
     * @param $err
     */
    private function errorLog($err) {
        $sql = <<<SQL
UPDATE buy_bill SET err_log=array_append(err_log,:err) WHERE bill_id=:id
SQL;
        Db::query($sql, ['id' => $this->bill_id, 'err' => $err]);
    }

    /**
     * 购买支付后续处理
     */
    public function afterBought() {

        $class = self::getBuyItem($this->bill_item_type);

        $class::afterBought($this->bill_id, $this->bill_user, $this->bill_item_id, $this);

        if (isset($this->gifts)) {
            foreach (Gifts::FIELDS as $field => $type) {
                $class = self::getBuyItem($type);
                $items = $this->gifts->$field ?? null;
                if ($items && is_array($items)) {
                    foreach ($items as $id) {
                        if ($class::checkBought($this->bill_user, $id)) continue;
                        $class::afterBought($this->bill_id, $this->bill_user, $id, $this);
                    }
                }
            }
        }
    }

    public function successMessage() {
        // 根据不同类型产生不同内容
        $serverTel = SysConfiguration::getServiceTel();
        switch ($this->bill_type) {
            case self::BILL_TYPE_CASH_PAY:
                $content = sprintf('恭喜您，成功购买了%s，花费%s元，服务热线%s。',$this->bill_item_title,$this->bill_pay_amount,$serverTel);
                break;
            case self::BILL_TYPE_CREDIT_EXCHANGE:
                $content = sprintf('恭喜您，成功兑换了%s，花费%d积分，服务热线%s。',$this->bill_item_title,$this->credit_cost,$serverTel);
                break;
            case self::BILL_TYPE_CREDIT_CASH:
                $content = sprintf('恭喜您，成功购买了%s，花费%s元+%d积分，服务热线%s。',$this->bill_item_title,$this->bill_pay_amount,$this->credit_cost,$serverTel);
                break;
            case self::BILL_TYPE_GIFT:
                $content = sprintf('恭喜您获得赠送的%s，服务热线%s。',$this->bill_item_title,$serverTel);
                break;
            default: return;
        }

        // 发出通知，短信和推送
        $extras = UserNoticeMessage::makeExtras(ConstLinkType::LINK_TYPE_BILL,$this->bill_id);
        UserNoticeMessage::addMsg($this->bill_user,'订单消息', $content,UserNoticeMessage::MESSAGE_TYPE_SYSTEM,$extras);
        JPushZDY::pushUsers($this->bill_user, $content, $extras);
//        $user = Users::get($this->bill_user);
//        ServerAPI::getInstance()->sendMessage(ServerAPI::TEMPLATE_BUY_SUCCESS,[$user->mobile],[$this->bill_item_title,$this->bill_pay_amount.'元',$serverTel]);
    }

    /**
     * 支付成功后的订单处理
     * 完成后直接打印字符串退出
     *
     * @return bool
     */
    public function successPay() {

        try{
            Db::startTrans();
            // 需要更新的字段
            if (PayFactory::APPLEPAY == $this->bill_pay_method && isset($this->apple_pay->price)) {
                $this->bill_pay_amount = $this->apple_pay->price;
            }
            if (empty($this->bill_paytime)) $this->bill_paytime = time();
            $this->bill_have_paid = true;
            $this->save();

            // 产生订单
            $this->afterBought();

            // 现金支付的购买要添加返积分和推广员奖励积分
            if (self::BILL_TYPE_CASH_PAY == $this->bill_type) {
                // 积分任务
                Users::creditTask($this->bill_user,UserCreditRecord::CHANGE_TYPE_BUY_REBATE, ['bill_id'=>$this->bill_id,'bill_pay_amount'=>$this->bill_pay_amount]);
                // 推广订单
                if($person=Users::findOne(['id'=>$this->bill_user],'promoter_id')){
                    if($person->promoter_id){
                        DrawPercentageRecord::addRecord(
                            [
                                'bill_user'=>$this->bill_user,
                                'promoter_id'=>$person->promoter_id,
                                'bill_id'=>$this->bill_id,
                                'bill_no'=>$this->bill_no,
                                'draw_percentage_price'=>sprintf("%.2f", ($this->bill_pay_amount)*config('proportion'))
                            ]
                        );
                    }
                }
            }
            // 赠送商品不发消息
            $this->successMessage();

            Db::commit();

            return true;
        }catch (\Exception $ex){
            Db::rollback();
            $this->errorLog($ex->getMessage());
            Log::error($ex);
            return false;
        }
    }

    /**
     * 创建合同
     * @deprecated
     */
    public function createContract() {


        $user = Users::get($this->bill_user);
        $mobile = $user->mobile;

        $auth = RealNameAuthentication::get(['user_id' => $user->id]);
        $realName = $auth->realname;
        $cardNo = $auth->identity_card_number;

        $contractNo = contractSignature::generateNo(Contract::getLastNo());

        $price = $this->bill_pay_amount;
        $productName = $this->bill_item_title;

        $result = contractSignature::get_instance()
            ->createPdf($contractNo, $realName, $cardNo, $mobile,
                $price, $productName);

        Contract::create([
            'contract_no' => $contractNo,
            'bill_id' => $this->bill_id,
            'realname_auth_id' => $auth->id,
            'contract_file' => contractSignature::fixUrl($result['outPath']),
            'contract_time' => time(),
        ]);
    }

    /**
     * @deprecated
     *
     * 彻底删除订单，需要谨慎
     *
     * @param $bill_id
     */
    public function delBill($bill_id) {

        try{
            Db::startTrans();

            $sql = <<<SQL
DELETE FROM user_buy_curriculum_level
WHERE ucl_user_buy_curriculum IN (
  SELECT uc_id
  FROM user_buy_curriculum
  WHERE uc_bill = :bill_id
)
SQL;
            Db::execute($sql, ['bill_id' => $bill_id]);

            $sql = 'DELETE FROM user_buy_curriculum WHERE uc_bill = :bill_id';
            Db::execute($sql, ['bill_id' => $bill_id]);

            $sql = 'DELETE FROM contract WHERE bill_id = :bill_id';
            Db::execute($sql, ['bill_id' => $bill_id]);

            $sql = 'DELETE FROM buy_bill WHERE bill_id = :bill_id';
            Db::execute($sql, ['bill_id' => $bill_id]);

            Db::commit();
        }catch (Exception $ex){
            Log::error('删除订单失败：'.$ex->getMessage());
            Db::rollback();
        }

    }

    /**
     * 添加推广订单
     */
    public function addAgencyBill() {

        // 获取邀请记录
        $aiu = Db::table('agency_invite_user aiu')
            ->join('agency_salesman sm','sm.id=aiu.salesman_id')
            ->where('aiu.userid','=', $this->bill_user)
            ->field('aiu.salesman_id,aiu.agency_id,sm.userid inviter')
            ->find();
        if (empty($aiu)) return;

        // 写入推广订单
        Db::table('agency_bill')->insert([
            'bill_id' => $this->bill_id,
            'salesman_id' => $aiu['salesman_id'],
            'agency_id' => $aiu['agency_id'],
        ]);

        // 增加累计推广金额
        Db::query('UPDATE agency_salesman SET accumulated_bill_amount = accumulated_bill_amount + :inc WHERE id=:id', [
            'id' => $aiu['salesman_id'],
            'inc' => $this->bill_pay_amount,
        ]);

        $credit = Users::creditTask($aiu['inviter'],UserCreditRecord::CHANGE_TYPE_INVITE_BUY_REBATE, ['bill_id'=>$this->bill_id,'bill_pay_amount'=>$this->bill_pay_amount]);
        $user = Users::get($this->bill_user);
        UserNoticeMessage::sendInviteBuyMessage($aiu['inviter'], $user->mobile, $this->bill_item_title, $credit);
    }

    /**
     * confirmBill
     * 确认订单展示数据
     *
     * @author zhengkai
     * @date 2018-02-27
     *
     * @param int $goodsType 商品类型：1=课程 2=直播 3=专栏
     * @param int $goodsId 商品id
     * @return array|false|\PDOStatement|string|Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function confirmBill($goodsType, $goodsId)
    {
        switch ($goodsType) {
            case self::BUY_ITEM_CURRICULUM: // 课程
                $data = Db::table('curriculum c')
                    ->join('curriculum_class cc', 'c.curriculum_class=cc.class_id', 'left')
                    ->where('c.curriculum_id', $goodsId)
                    ->field('
                    c.curriculum_id as goods_id,
                    c.curriculum_name as goods_name,
                    cc.class_name as goods_class,
                    c.curriculum_type as goods_course_type,
                    c.curriculum_level as goods_course_level,
                    c.curriculum_suit_user as goods_suit_user,
                    c.curriculum_episode_number as goods_video_total,
                    c.curriculum_pic as goods_pic,
                    c.curriculum_sale_price as goods_sale_price,
                    c.curriculum_market_price as goods_markey_price,
                    c.curriculum_sales as goods_sales,
                    c.apple_pay_price,
                    c.apple_pay_production_id,
                    c.service_enable
                    ')
                    ->find();
                if (empty($data)) return null;
                if ($data['service_enable']) {
                    $bindService = CourseBindService::get($data['goods_id']);
                    $data['bindService']['expired'] = $bindService->expired.'天';
                    $re = Db::query('select t.realname AS teacher_name from curriculum_video v JOIN teacher t ON v.video_teacher=t.id where v.video_curriculum=:cid GROUP BY t.id,t.realname limit 1',
                        ['cid' => $data['goods_id']]);
                    $data['bindService']['teacher'] = $re[0]['teacher_name'] ?? '';
                }

                switch ($data['goods_course_level']) {
                    case 1:
                        $data['goods_course_level'] = '初级';
                        break;
                    case 2:
                        $data['goods_course_level'] = '中级';
                        break;
                    case 3:
                        $data['goods_course_level'] = '高级';
                        break;
                }

                $data['goods_type'] = (int)$goodsType;

                $data['goods_pay_price'] = $data['goods_sale_price'];

                $data['apple_pay'] = self::applePayObject($data['apple_pay_price'],$data['apple_pay_production_id']);
                unset($data['apple_pay_price'],$data['apple_pay_production_id']);

                // 优惠折扣、赠品数据处理 =====
                $now = time();
                if ($data['goods_sales']>0) {
                    // 查询出商品优惠促销数据
                    $sales = Db::query("select * from sales where sales_id={$data['goods_sales']}");
                    $sales = $sales[0];

                    if ($now>$sales['sales_start_time'] && $now<$sales['sales_end_time']) {
                        // 折扣、金额减免处理
                        switch ($sales['sales_type']) {
                            case 1: // 折扣
                                $data['goods_sales_info'] = round(((int)$sales['sales_discount']/10), 1).'折';
                                $data['goods_pay_price'] = round(((int)$sales['sales_discount']/100)*$data['goods_sale_price'], 2);
                                break;
                            case 2: // 现金减免
                                $data['goods_sales_info'] = '直降'.$sales['sales_amount'].'元';
                                $data['goods_pay_price'] = round(($data['goods_sale_price']-$sales['sales_amount']), 2);
                                break;
                            default:
                                $data['goods_sales_info'] = '';
                                $data['goods_pay_price'] = $data['goods_sale_price'];
                        }

                        // 赠品
                        $data['goods_give'] = \app\api\model\Sales::gift($data['goods_sales']);
                    } else {
                        $data['goods_sales_info'] = '';
                        $data['goods_give'] = [];
                    }
                }  else {
                    $data['goods_sales_info'] = '';
                    $data['goods_give'] = [];
                }
                // 优惠折扣、赠品数据处理 =====
                break;
            case self::BUY_ITEM_LIVE: // 直播
                break;
            case self::BUY_ITEM_SPECIAL: // 专栏
                $data = Db::table('special_column')
                    ->where('column_id', $goodsId)
                    ->field('
                    column_id as goods_id,
                    column_title as goods_name,
                    covers->>\'list\' as goods_pic,
                    column_price as goods_sale_price,
                    column_sales as goods_sales,
                    column_expiry as goods_expiry_day,
                    apple_pay_price,
                    apple_pay_production_id
                    ')
                    ->find();
                if (empty($data)) return null;

                $data['goods_type'] = (int)$goodsType;
                $data['goods_pay_price'] = $data['goods_sale_price'];
                if (!empty($data['apple_pay_production_id']))
                $data['apple_pay'] = self::applePayObject($data['apple_pay_price'], $data['apple_pay_production_id']);

                // 优惠折扣、赠品数据处理 =====
                $now = time();
                if ($data['goods_sales']>0) {
                    // 查询出商品优惠促销数据
                    $sales = Db::query("select * from sales where sales_id={$data['goods_sales']}");
                    $sales = $sales[0];
                    /*$sales = Db::table('sales')
                        ->where('sales_id', $data['goods_sales'])
                        ->where(function($query)use ($now){
                            $query->where('sales_start_time', '<', $now)
                                ->where('sales_end_time', '>', $now);
                        })
                        ->find();*/

                    if ($now>$sales['sales_start_time'] && $now<$sales['sales_end_time']) {
                        // 折扣、金额减免处理
                        switch ($sales['sales_type']) {
                            case 1: // 折扣
                                $data['goods_sales_info'] = round(((int)$sales['sales_discount']/10), 1).'折';
                                $data['goods_pay_price'] = round(((int)$sales['sales_discount']/100)*$data['goods_sale_price'], 2);
                                break;
                            case 2: // 现金减免
                                $data['goods_sales_info'] = '直降'.$sales['sales_amount'].'元';
                                $data['goods_pay_price'] = round(($data['goods_sale_price']-$sales['sales_amount']), 2);
                                break;
                            default:
                                $data['goods_sales_info'] = '';
                                $data['goods_pay_price'] = $data['goods_sale_price'];
                        }

                        // 赠品
                        $data['goods_give'] = \app\api\model\Sales::gift($data['goods_sales']);
                    } else {
                        $data['goods_sales_info'] = '';
                        $data['goods_give'] = [];
                    }
                } else {
                    $data['goods_sales_info'] = '';
                    $data['goods_give'] = [];
                }
                // 优惠折扣、赠品数据处理 =====
                break;
        }


        return $data ?? null;
    }

    /**
     * 我购买的订单
     * @param int $uid
     * @param int $rows
     * @param int $page
     * @param bool $pageTotal
     * @param string $payStatus
     * @return mixed
     */
    public static function myBill(int $uid, int $rows = 10, int $page = 1, $pageTotal = false, $payStatus='') {

        $query = Db::table('buy_bill b')
            ->join('contract c','b.bill_id=c.bill_id','LEFT')
            ->join('user_buy_curriculum buc','b.bill_id=buc.uc_bill','left')
            ->join('zds_order zo','b.bill_id=zo.billid','left')
            ->where('b.bill_user','=',$uid)
            ->where(function ($query) use ($payStatus) {
                if ($payStatus==='n') {
                    $query->where("b.bill_have_paid=false");
                } else if ($payStatus==='y') {
                    $query->where("b.bill_have_paid=true");
                }
            })
            ->order('b.bill_id','DESC')
            ->field('
            b.bill_id,
            b.bill_no,
            b.bill_have_paid as pay_status,
            b.bill_item_type as item_type,
            b.bill_item_id as item_id,
            b.bill_item_title as title,
            b.bill_createtime as create_time,
            b.bill_payable_amount as payable_amount,
            b.bill_pay_amount as pay_amount,
            b.apple_pay,
            b.bill_paytime,
            b.bill_item_id,
            c.contract_no,
            c.contract_file,
            c.contract_time,
            buc.service_expired
            ')
        ;

        $result = $query->paginate($rows,false,['page'=>$page]);
        $list = $result->items();
        $total = $result->total();

        foreach ($list as & $item) {
            $item['payable_amount'] = floatval($item['payable_amount']);
            $item['pay_amount'] = floatval($item['pay_amount']);
            $item['pay_status'] = $item['pay_status']?1:0;
            $item['create_time'] = date('Y-m-d', $item['create_time']);
            if ($item['contract_no']) {
                $item['contract_time'] = date('Y-m-d H:i', $item['contract_time']);
            }
            $item['apple_pay'] = json_decode($item['apple_pay']);
            //fix bug--获取不到到期时间
            if(!$item['service_expired']){
                $item['service_rang'] = '-';
            }else{
                $item['service_rang']=date('Y-m-d',$item['bill_paytime']).'~'.date('Y-m-d',$item['service_expired']);
            }
            $teachers=$item['item_type']==1 ? Curriculum::getTeacher($item['bill_item_id'], 't.realname') : '';
            $item['teacher'] = $teachers?$teachers[0]['realname']:"";
        }

        return ['list'=>$list,'total'=>$total];
    }

    /**
     * billDetail
     * 订单详情数据
     *
     * @author zhengkai
     * @version 1.3.2
     * @date 2018-02-24
     *
     * @param int $uid 用户id
     * @param int $billId 订单id
     * @return array
     */
    public static function billDetail($uid, $billId)
    {
        // 查询订单数据
        $bill = self::get(function ($query) use ($uid, $billId) {
           $query->where('bill_id', $billId)
               ->where('bill_user', $uid);
        });
        if (empty($bill)) return null;

        // 根据订单商品类型查询商品数据
        switch ($bill->bill_item_type) {
            case self::BUY_ITEM_CURRICULUM: // 课程
                $goods = Db::table('curriculum c')
                    ->join('curriculum_class cc', 'c.curriculum_class=cc.class_id', 'left')
                    ->where('c.curriculum_id', $bill->bill_item_id)
                    ->field('
                    c.curriculum_id as goods_id,
                    c.curriculum_name as goods_name,
                    cc.class_name as goods_course_class,
                    c.curriculum_suit_user as goods_suit_user,
                    c.curriculum_episode_number as goods_video_total,
                    c.curriculum_pic as goods_pic,
                    c.curriculum_type as goods_course_type,
                    c.curriculum_level as goods_course_level,
                    c.curriculum_sale_price as goods_slae_price,
                    c.curriculum_market_price as goods_market_price,
                    c.service_enable
                    ')
                    ->find();
                if ($bill->bill_have_paid) {
                    $bindService = CourseBindService::getEnableService($uid, $goods['goods_id']);
                    if ($bindService) {
                        $goods['service_enable'] = true;
                        $goods['bindService']['expired'] = date('Y-m-d', $bill->bill_paytime).'~'.date('Y-m-d', $bindService->service_expired);
                    }
                } elseif ($goods['service_enable']) {
                    $bindService = CourseBindService::get($goods['goods_id']);
                    $goods['bindService']['expired'] = $bindService->expired.'天';
                }
                if ($goods['service_enable']) {
                    $re = Db::query('select t.realname AS teacher_name from curriculum_video v JOIN teacher t ON v.video_teacher=t.id where v.video_curriculum=:cid GROUP BY t.id,t.realname limit 1',
                        ['cid' => $goods['goods_id']]);
                    $goods['bindService']['teacher'] = $re[0]['teacher_name'] ?? '';
                }

                switch ($goods['goods_course_level']) {
                    case 1:
                        $goods['goods_course_level'] = '初级';
                        break;
                    case 2:
                        $goods['goods_course_level'] = '中级';
                        break;
                    case 3:
                        $goods['goods_course_level'] = '高级';
                        break;
                }
                break;
            case self::BUY_ITEM_SPECIAL: // 专栏
                $goods = Db::table('special_column')
                    ->where('column_id', $bill->bill_item_id)
                    ->field('
                    column_id as goods_id,
                    column_title as goods_name,
                    covers->>\'list\' as goods_pic,
                    column_expiry as goods_expiry_day,
                    column_price as goods_slae_price
                    ')
                    ->find();
                break;
            default:
                return null;
        }

        // 赠送数据处理
        if (count($bill['gifts'])) {
            $giveArr = [];
            $courseArr = [];
            $columnArr = [];
            foreach ($bill['gifts'] as $key=>$val) {
                switch ($key) {
                    case 'curricula': // 赠送课程
                        // 获取赠送课程数据
                        $courseId = implode(',', $val);
                        $giveCourse = Db::query("select 
c.curriculum_id as item_id, 
c.curriculum_name as item_title,
cc.class_name as item_class,
c.curriculum_type as item_course_type,
c.curriculum_level as item_course_level,
c.curriculum_suit_user as item_suit_user,
c.curriculum_market_price as item_market_price,
c.curriculum_sale_price as item_sale_price,
c.curriculum_pic as item_cover,
c.curriculum_episode_number as item_video_total
from curriculum as c
left join curriculum_class cc on c.curriculum_class=cc.class_id
where c.curriculum_id in ({$courseId})");
                        foreach ($giveCourse as $course_key=>$course_val) {
                            // $course_val['item_type'] = 1;
                            switch ($course_val['item_course_level']) {
                                case 1:
                                    $course_val['item_course_level'] = '初级';
                                    break;
                                case 2:
                                    $course_val['item_course_level'] = '中级';
                                    break;
                                case 3:
                                    $course_val['item_course_level'] = '高级';
                                    break;
                            }
                            $courseArr[$course_key]['item_type'] = 1;
                            $courseArr[$course_key]['goods_course'] = $course_val;
                            $courseArr[$course_key]['goods_column'] = (object)[];
                        }
                        break;
                    case 'columns': // 赠送专栏
                        // 获取赠送专栏数据
                        $columnId = implode(',', $val);
                        $giveCourse = Db::query("select 
column_id as item_id, 
column_title as item_title,
column_price as item_sale_price,
column_expiry as item_expiry_day,
covers->>'list' as item_cover
from special_column where column_id in ({$columnId})");
                        foreach ($giveCourse as $column_key=>$column_val) {
                            // $cloumn_val['item_type'] = 3;
                            $columnArr[$column_key]['item_type'] = 3;
                            $columnArr[$column_key]['goods_course'] = (object)[];
                            $columnArr[$column_key]['goods_column'] = $column_val;
                        }
                        break;
                }
                $giveArr = array_merge($courseArr, $columnArr);
            }
        } else {
            $giveArr = [];
        }

        $data = [
            'bill_no' => $bill->bill_no,
            'bill_createtime' => date('Y-m-d H:i', $bill['bill_createtime']),
            'bill_paytime' => date('Y-m-d H:i', $bill['bill_paytime']),
            'payable_amount' => $bill->bill_payable_amount,
            'pay_amount' => $bill->bill_pay_amount,
            'discount_amount' => round(($bill->bill_payable_amount - $bill->bill_pay_amount), 2),
            'bill_integral' => intval($bill->bill_pay_amount * 0.5),
            'pay_status' => $bill['bill_have_paid']?1:0,
            'bill_goods_id' => $bill['bill_item_id'],
            'bill_goods_type' => $bill['bill_item_type'],
            'apple_pay' => $bill->apple_pay,
            'bill_goods' => $goods,
            'bill_give' => $giveArr,
        ];

        return $data;
    }

    /**
     * 我推广的客户购买订单
     * @param int $uid
     * @param string $month
     * @param int $rows
     * @param int $page
     * @param bool $pageTotal
     * @return mixed
     *
     * @todo v1.4.1废弃
     */
    public static function myAgencyBill(int $uid, string $month, int $rows = 10, int $page = 1, $pageTotal = false) {

        $salesman = Db::table('agency_salesman')
            ->where('userid','=', $uid)
            ->field('id as salesman_id, agency_id')
            ->find();
        if (empty($salesman)) return ['list'=>[],'total'=>0,'month_total_amount'=>0,'total_amount'=>0];

        $start = strtotime(date('Y-m-d', strtotime($month)));
        $end = strtotime(date('Y-m-d', strtotime($month.' +1 month')));

        $query = Db::table('buy_bill b')
            ->join('agency_bill ab','ab.bill_id=b.bill_id')
            ->join('users u','u.id=b.bill_user')
            ->where('b.bill_have_paid=true')
            ->where('ab.salesman_id','=', $salesman['salesman_id'])
            ->where('ab.agency_id','=', $salesman['agency_id']);
        $querySum = clone $query;
        $querySumTotal = clone $query;

        $query->where('b.bill_createtime','between', [$start, $end])
            ->order('b.bill_id','DESC')
            ->field('
            b.bill_id,
            b.bill_item_title as title,
            b.bill_createtime as create_time,
            b.bill_pay_amount as pay_amount,
            u.mobile as customer
            ')
        ;

        $month_total_amount = $querySum->sum('b.bill_pay_amount');
        $total_amount = $querySumTotal->sum('b.bill_pay_amount');

        if ($pageTotal) {
            $result = $query->paginate($rows,false,['page'=>$page]);
            $list = $result->items();
            $total = $result->total();
        } else {
            $list = $query->page($page, $rows)->select();
            $total = null;
        }

        foreach ($list as & $item) {
            $item['create_time'] = substr($item['create_time'], 0,10);
        }

        return [
            'list' => $list,
            'total' => $total,
            'month_total_amount' => strval(round($month_total_amount,2)),
            'total_amount' => $total_amount,
        ];
    }

    /**
     * @param $uid
     * @param $item_type
     * @param $item_id
     * @param $pay_method
     * @param $pay_amount
     * @param $pay_trade_no
     * @param $pay_time
     * @param $bill_type
     * @return static
     * @throws Exception
     */
    public static function addBill($uid, $item_type, $item_id, $pay_method, $pay_amount, $pay_trade_no, $pay_time, $bill_type) {

        if (self::checkBought($item_type, $uid, $item_id)) {
            throw new Exception("用户{$uid}已经拥有课程【{$item_id}】");
        }

        $item = self::getBuyInfo($item_type, $uid, $item_id);
        if (empty($item)) throw new Exception('课程不存在: id=' . $item_id);

        $orderNo = self::generateOrderNo($uid);
        $bill = self::create([
            'bill_no' => $orderNo,
            'bill_user' => $uid,
            'bill_item_type' => $item_type,
            'bill_item_id' => $item_id,
            'bill_source' => 0,
            'bill_pay_method' => $pay_method,
            'bill_pay_amount' => $pay_amount,
            'bill_payable_amount' => $item['price_orig'],
            'bill_item_title' => $item['title'],
            'bill_item_detail' => $item['detail'],
            'bill_createtime' => time(),
            'pay_trade_no' => $pay_trade_no,
            'bill_paytime' => $pay_time,
            'bill_trade_way' => self::TRADE_WAY_OFFLINE,
            'bill_type' => $bill_type
        ]);

        return self::get($bill->bill_id);
    }

    /**
     * 赠送课程快捷方法，赠送内容由管理后台配置
     *
     * @param $uid
     * @return BuyBill
     */
    public static function addBillGift($uid) {
        $config = SysConfiguration::userRegisterGift();
        if (!$config) return false;
        if (!$config->enable) return null;

        $bill = self::addBill($uid, $config->type, $config->id, 0, '0.00', '', time(), self::BILL_TYPE_GIFT);
        $bill->successPay();
        return $bill;
    }

    /**
     * 购买订单的管理列表
     *
     * @param $rows
     * @param $page
     * @param int $finished
     * @param int $start
     * @param int $end
     * @param bool $export
     * @param null $bill_no
     * @param null $mobile
     * @param int $itemType
     * @param int $pay
     * @return mixed
     */
    public static function manageList(
        $rows, $page, $finished = -1, $start = 0, $end = 0, $export = false, $bill_no = null, $mobile = null,
        $itemType = 0, $pay = 0
    ) {

        $q = Db::table('buy_bill b')->join('users u','b.bill_user=u.id');
        $q->join('buy_bill_vip v','v.bv_bill_id=b.bill_id','LEFT');
//        $q->join('agency_bill ab','ab.bill_id=b.bill_id','LEFT');
//        $q->join('agency a','a.id=ab.agency_id','LEFT');
        $q->join('zds_order zo','zo.billid = b.bill_id','LEFT');
        $q->join('zds_agency za','zo.agencyid=za.id','LEFT');
        $q->join('zds_salesman zs','zo.salesmanid=zs.id','LEFT');

        $q->where('b.is_sandbox=false');
        $q->where('b.bill_type=1');
        $q->order('b.bill_id','desc');
        $q->field('
            b.bill_id,
            b.bill_item_type,
            b.bill_item_id,
            b.bill_item_title,
            b.bill_item_detail,
            b.bill_no,
            b.bill_payable_amount,
            b.bill_pay_amount,
            b.credit_cost,
            b.bill_trade_way,
            b.bill_type,
            b.bill_paytime,
            b.bill_createtime,
            b.bill_pay_method,
            b.bill_source,
            b.bill_trade_way,
            b.bill_have_paid,
            u.mobile,
            v.bv_id is not null as is_vip,
            zo.agencyid,
            za.name as agency_name
        ');
        if ($itemType) {
            $q->where('b.bill_item_type','=', $itemType);
        }
        if ($pay != 0) {
            $q->where('b.bill_pay_method','=', $pay);
        }
        if ($bill_no) {
            $q->whereLike('b.bill_no',"{$bill_no}%");
        }
        if ($mobile) {
            $q->whereLike('u.mobile',"{$mobile}%");
        }
        if (0==$finished || 1==$finished) {
            $q->where('b.bill_have_paid','=', $finished);
        }
        if ($start>0 && $end>0 && $start<$end) {
            $q->whereBetween('b.bill_createtime', [$start, $end]);
        }

        if ($export) {
            // 不分页
            $re = $q->select();
            foreach ($re as & $item) {
                self::format($item);
            }
        } else {
            // 分页
            $re = $q->paginate($rows,false, ['page' => $page])->toArray();

            foreach ($re['data'] as & $item) {
                self::format($item);
            }
        }

        return $re;
    }

    public static function sumByItem(int $start = 0, int $end = 0) {
        $where = '';
        $params = [];
        if ($start>0 && $end>0) {
            $where .= ' AND bill_paytime BETWEEN :ts AND :te ';
            $params['ts'] = $start;
            $params['te'] = $end;
        }
        $sql = <<<SQL
SELECT
  bill_item_type item_type,
  sum(bill_pay_amount) pay_amount,
  count(*) num
FROM buy_bill
WHERE bill_have_paid AND is_sandbox=false {$where} and bill_type=1
GROUP BY bill_item_type
SQL;
        $list = Db::query($sql,$params);

        $num = 0;
        $amount = 0.0;
        foreach ($list as & $item) {
            $item['item_name'] = self::getBuyItemName($item['item_type']);
            $amount += $item['pay_amount'];
            $num += $item['num'];
        }
        $amount = round($amount,2);

        return ['amount' => $amount, 'num' => $num, 'list' => $list];
    }

    private static function format(array & $item) {
        $item['bill_pay_method'] = PayFactory::getPayName($item['bill_pay_method']);
        $item['bill_paytime'] = date('Y-m-d H:i', $item['bill_paytime']);
        $item['bill_createtime'] = date('Y-m-d H:i', $item['bill_createtime']);
        $item['bill_item_type'] = self::getBuyItemName($item['bill_item_type']);
        $item['bill_trade_way'] = self::getTradeWayName($item['bill_trade_way']);
        $item['bill_type'] = self::getBuyTypeName($item['bill_type']);
    }
    /**
     * billDetail
     * 订单合同数据
     * cc 2018-10-30
     */
    public static function contractData($uid, $billId)
    {
        // 查询订单数据
        $bill = self::where(['bill_id'=>$billId,'bill_user'=>$uid])
              ->field('bill_item_type')
              ->find() ;

        if (empty($bill)) return null;
        //服务类型数组
        $service_arr = [
            'bind_column_id' => '名师专栏',
            'online_course' => '线上课程（每周一次）',
            'fupan_answer' => '复盘解惑（每周一次）',
            'exclusive_group' =>'专属群服务',
            'stock_analysis_report' =>'个股分析报告',
            'article_reference' =>'内参',
            'article_report' =>'研报'
        ];

        // 根据订单商品类型查询商品数据
        switch ($bill->bill_item_type) {
            case self::BUY_ITEM_CURRICULUM: // 课程
                $goods = Db::table('buy_bill b')
                    ->join('zds_order zo', 'b.bill_no=zo.billno', 'left')
                    ->join('users u', 'b.bill_user=u.id', 'left')
                    ->join('zds_agency za', 'za.id=zo.agencyid', 'left')
                    ->where('b.bill_id', $billId)
                    ->field('
                       za.name as agency_name,za.telephone as agency_mobile,u.realname as user_name,u.mobile as user_mobile,
                       b.bill_item_title,zo.service_start_time,zo.service_end_time,b.bill_payable_amount,b.bill_pay_amount,
                       b.bill_item_id,b.bill_createtime
                    ')
                    ->find();
                //处理课程服务项目
                $res = Db::table('course_bind_service')
                    ->field(implode(',',array_keys($service_arr)))
                    ->where('curriculum_id',$goods['bill_item_id'])->find();
                $serviceArr =[];
                if($res){
                    foreach ($res as $k=>$v){
                        if($v){
                            $serviceArr[] = $service_arr[$k];
                        }
                    }
                }

                $serviceArr = array_filter(array_unique($serviceArr));

                $goods['service_text'] = implode('/',$serviceArr);
                //设置服务日期
                //$goods['service_start'] = $goods['service_start_time']?date('Y年m月d日',strtotime($goods['service_start_time'])):"";
                //$goods['service_end'] = $goods['service_end_time']?date('Y年m月d日',strtotime($goods['service_end_time'])):"";
                $goods['service_start_year'] = $goods['service_start_time']?date('Y',strtotime($goods['service_start_time'])):"";
                $goods['service_start_month'] = $goods['service_start_time']?date('m',strtotime($goods['service_start_time'])):"";
                $goods['service_start_day'] = $goods['service_start_time']?date('d',strtotime($goods['service_start_time'])):"";
                $goods['service_end_year'] = $goods['service_end_time']?date('Y',strtotime($goods['service_end_time'])):"";
                $goods['service_end_month'] = $goods['service_end_time']?date('m',strtotime($goods['service_end_time'])):"";
                $goods['service_end_day'] = $goods['service_end_time']?date('d',strtotime($goods['service_end_time'])):"";
                //获取合同编号
                $number = self::getNumber($goods['bill_createtime']);
                $goods['contract_no'] = 'ZQJY-XS-'.date('Ymd',$goods['bill_createtime']).$number;

                //转换大写人民币
                $goods['pay_amount_cny'] = changeCny($goods['bill_pay_amount']);
                $goods['payable_amount_cny'] = changeCny($goods['bill_payable_amount']);
                //去除无用数据
                unset($goods['service_start_time']);
                unset($goods['service_end_time']);
                unset($goods['bill_item_id']);

                break;
            default:
                return null;
        }

        return $goods;
    }
    //获取订单的数字序号--当天的第几个订单
    public static function getNumber($created){
        $start = date('Y-m-d',$created);

        $res = Db::table('buy_bill')
            ->field('bill_id')
            ->where('bill_createtime <='.$created)
            ->where('bill_createtime >='.strtotime($start))
            ->count();
        return str_pad($res,3,"0",STR_PAD_LEFT);
    }
}
